/**
  ******************************************************************************
  * @file           
  * @author         古么宁
  * @brief          IEC101 链路层解析
  ******************************************************************************
  *
  * COPYRIGHT(c) 2019 GoodMorning
  *
  ******************************************************************************
  */
/* Includes ---------------------------------------------------*/

#include <string.h>

#include "iec10x.h"
#include "iec10x_link.h"
#include "iec10x_debug.h"

#include "../iec/str.h"
#include "../iec/devif.h"

#include "COT.h"
#include "ASDUTYP.h"
#include "SIQ.h"
#include "DIQ.h"
#include "STD.h"

#if (ENABLE_PKT_PARSER)

/* Private types ------------------------------------------------------------*/

typedef int (*parsefn_t)(iec10x_t * bus , uint8_t num, uint32_t * addrlist ,void * data);


/* Private macro ------------------------------------------------------------*/

/* Private variables --------------------------------------------------------*/

/** 大部分内容数据的 ASDU 类型小于 64 ， 此处最多解析 < 64 那部分 */
static parsefn_t data_parser[64] = {0};

/* Private function prototypes ----------------------------------------------*/
static void unbals_link_check(iec10x_t * bus, uint8_t ) ;
static void unbalm_link_check(iec10x_t * bus, uint8_t ) ;
static void bals_link_check  (iec10x_t * bus, uint8_t ) ;
static void balm_link_check  (iec10x_t * bus, uint8_t ) ;



int SIQ0T_parse(iec10x_t * bus , uint8_t num, uint32_t * addrlist ,void * data)
{
	SIQ0T_t * info = (SIQ0T_t *)data;
	if (bus->dbglevel > IEC_DBG_HIGH) {
		for (int i = 0 ; i < num ; ++i,++info){
			SIQ_t * SIQ = &info->SIQ;
			bus->printf("addr:0x%x,val:0x%x\r\n",addrlist[i],*info);
			bus->printf("SPI%s,"  ,SPIinfo[SIQ->part.SPI]);
			bus->printf("BL%s,"   ,BLinfo[SIQ->part.BL]);
			bus->printf("SB%s,"   ,SBinfo[SIQ->part.SB]);
			bus->printf("NT%s,"   ,NTinfo[SIQ->part.NT]);
			bus->printf("IV%s\r\n"  ,IVinfo[SIQ->part.IV]);
		}
	}
	else {
		for (int i = 0 ; i < num ; ++i,++info){
			bus->printf("addr:0x%x,val:0x%x\r\n",addrlist[i],*info);
		}
	}

	return 0;
}

int SIQ24T_parse(iec10x_t * bus , uint8_t num, uint32_t * addrlist ,void * data)
{
	SIQ24T_t * info = (SIQ24T_t *)data;
	if (bus->dbglevel > IEC_DBG_HIGH) {
		for (int i = 0 ; i < num ; ++i,++info){
			SIQ_t * SIQ = &info->SIQ;
			bus->printf("addr:0x%x,val:0x%x,",addrlist[i],info->SIQ.val);
			bus->printf("t:%d %d\r\n",
				info->time.min,(info->time.ms[1]<<8)|info->time.ms[0]);
			
			bus->printf("SPI%s,"  ,SPIinfo[SIQ->part.SPI]);
			bus->printf("BL%s,"   ,BLinfo[SIQ->part.BL]);
			bus->printf("SB%s,"   ,SBinfo[SIQ->part.SB]);
			bus->printf("NT%s,"   ,NTinfo[SIQ->part.NT]);
			bus->printf("IV%s\r\n"  ,IVinfo[SIQ->part.IV]);
		}
	}
	else {
		for (int i = 0 ; i < num ; ++i,++info){
			bus->printf("addr:0x%x,val:0x%x,",addrlist[i],info->SIQ.val);
			bus->printf("t:%d %d\r\n",
				info->time.min,(info->time.ms[1]<<8)|info->time.ms[0]);
		}
	}
	return 0;
}

int SIQ56T_parse(iec10x_t * bus , uint8_t num, uint32_t * addrlist ,void * data)
{
	SIQ56T_t * info = (SIQ56T_t * )data;
	if (bus->dbglevel > IEC_DBG_HIGH) {
		for (int i = 0 ; i < num ; ++i,++info){
			SIQ_t * SIQ = &info->SIQ;
			bus->printf("addr:0x%x,val:0x%x,",addrlist[i],info->SIQ.val);
			bus->printf("t:%d/%d/%d %d:%d\r\n",
				info->time.year,info->time.month,info->time.day.date ,
				info->time.hour,info->time.min);

			bus->printf("SPI%s,"  ,SPIinfo[SIQ->part.SPI]);
			bus->printf("BL%s,"   ,BLinfo[SIQ->part.BL]);
			bus->printf("SB%s,"   ,SBinfo[SIQ->part.SB]);
			bus->printf("NT%s,"   ,NTinfo[SIQ->part.NT]);
			bus->printf("IV%s\r\n"  ,IVinfo[SIQ->part.IV]);
		}
	}
	else {
		for (int i = 0 ; i < num ; ++i,++info){
			bus->printf("addr:0x%x,val:0x%x,",addrlist[i],info->SIQ.val);
			bus->printf("t:%d/%d/%d %d:%d\r\n",
				info->time.year,info->time.month,info->time.day.date ,
				info->time.hour,info->time.min);
		}
	}
	return 0;
}

int DIQ0T_parse(iec10x_t * bus , uint8_t num, uint32_t * addrlist ,void * data)
{
	DIQ0T_t * info = (DIQ0T_t *)data;
	if (bus->dbglevel > IEC_DBG_HIGH){
		for (int i = 0 ; i < num ; ++i,++info){
			DIQ_t * DIQ = &info->DIQ;
			bus->printf("addr:0x%x,val:0x%x\r\n",addrlist[i],*info);
			bus->printf("SPI%s,"  ,SPIinfo[DIQ->part.DPI]);
			bus->printf("BL%s,"   ,BLinfo[DIQ->part.BL]);
			bus->printf("SB%s,"   ,SBinfo[DIQ->part.SB]);
			bus->printf("NT%s,"   ,NTinfo[DIQ->part.NT]);
			bus->printf("IV%s\r\n"  ,IVinfo[DIQ->part.IV]);
		}
	}
	else {
		for (int i = 0 ; i < num ; ++i,++info){
			bus->printf("addr:0x%x,val:0x%x\r\n",addrlist[i],*info);
		}
	}
	return 0;
}

int DIQ24T_parse(iec10x_t * bus , uint8_t num, uint32_t * addrlist ,void * data)
{
	DIQ24T_t * info = (DIQ24T_t *)data;
	if (bus->dbglevel > IEC_DBG_HIGH){
		for (int i = 0 ; i < num ; ++i,++info){
			DIQ_t * DIQ = &info->DIQ;
			bus->printf("addr:0x%x,val:0x%x,",addrlist[i],info->DIQ.val);
			bus->printf("t:%d %d\r\n",
				info->time.min,(info->time.ms[1]<<8)|info->time.ms[0]);
			
			bus->printf("SPI%s,"  ,SPIinfo[DIQ->part.DPI]);
			bus->printf("BL%s,"   ,BLinfo[DIQ->part.BL]);
			bus->printf("SB%s,"   ,SBinfo[DIQ->part.SB]);
			bus->printf("NT%s,"   ,NTinfo[DIQ->part.NT]);
			bus->printf("IV%s\r\n"  ,IVinfo[DIQ->part.IV]);
		}
	}
	else {
		for (int i = 0 ; i < num ; ++i,++info){
			bus->printf("addr:0x%x,val:0x%x,",addrlist[i],info->DIQ.val);
			bus->printf("t:%d %d\r\n",
				info->time.min,(info->time.ms[1]<<8)|info->time.ms[0]);
		}
	}
	return 0;
}

int DIQ56T_parse(iec10x_t * bus , uint8_t num, uint32_t * addrlist ,void * data)
{
	DIQ56T_t * info = (DIQ56T_t * )data;
	if (bus->dbglevel > IEC_DBG_HIGH){
		for (int i = 0 ; i < num ; ++i,++info){
			DIQ_t * DIQ = &info->DIQ;
			bus->printf("addr:0x%x,val:0x%x,",addrlist[i],info->DIQ.val);
			bus->printf("t:%d/%d/%d %d:%d\r\n",
				info->time.year,info->time.month,info->time.day.date ,
				info->time.hour,info->time.min);

			bus->printf("SPI%s,"  ,SPIinfo[DIQ->part.DPI]);
			bus->printf("BL%s,"   ,BLinfo[DIQ->part.BL]);
			bus->printf("SB%s,"   ,SBinfo[DIQ->part.SB]);
			bus->printf("NT%s,"   ,NTinfo[DIQ->part.NT]);
			bus->printf("IV%s\r\n"  ,IVinfo[DIQ->part.IV]);
		}
	}
	else {
		for (int i = 0 ; i < num ; ++i,++info){
			bus->printf("addr:0x%x,val:0x%x,",addrlist[i],info->DIQ.val);
			bus->printf("t:%d/%d/%d %d:%d\r\n",
				info->time.year,info->time.month,info->time.day.date ,
				info->time.hour,info->time.min);
		}
	}
	return 0;
}

int STD0T_pro(iec10x_t * bus , uint8_t num, uint32_t * addrlist ,void * data)
{
	STD0T_t * info = (STD0T_t*)data;
	float val;
	uint32_t *valset = (uint32_t*)&val;
	if (bus->dbglevel > IEC_DBG_HIGH){
		for (int i = 0 ; i < num ; ++i,++info){
			STD_t  * STD = &info->STD;
			QDS_t  * QDS = &info->QDS;
			*valset = STD->val[0]|(STD->val[1]<<8)|(STD->val[2]<<16)|(STD->val[3]<<24);
			bus->printf("addr:0x%x,val:%f\r\n",addrlist[i],val);
			bus->printf("OV%s,"   ,OVinfo[QDS->part.OV]);
			bus->printf("BL%s,"   ,BLinfo[QDS->part.BL]);
			bus->printf("SB%s,"   ,SBinfo[QDS->part.SB]);
			bus->printf("NT%s,"   ,NTinfo[QDS->part.NT]);
			bus->printf("IV%s\r\n"   ,IVinfo[QDS->part.IV]);
		}
	}
	else {
		for (int i = 0 ; i < num ; ++i,++info){
			STD_t  * STD = &info->STD;
			*valset = STD->val[0]|(STD->val[1]<<8)|(STD->val[2]<<16)|(STD->val[3]<<24);
			bus->printf("addr:0x%x,val:%f\r\n",addrlist[i],val);
		}
	}
	return 0;
}

int STD24T_pro(iec10x_t * bus , uint8_t num, uint32_t * addrlist ,void * data)
{
	STD24T_t * info = (STD24T_t*)data;
	float val;
	uint32_t *valset = (uint32_t*)&val;
	if (bus->dbglevel > IEC_DBG_HIGH) {
		for (int i = 0 ; i < num ; ++i,++info){
			STD_t  * STD = &info->STD;
			QDS_t  * QDS = &info->QDS;
			*valset = STD->val[0]|(STD->val[1]<<8)|(STD->val[2]<<16)|(STD->val[3]<<24);
			bus->printf("addr:0x%x,val:%f,",addrlist[i],val);
			bus->printf("t:%d %d\r\n",
				info->time.min,(info->time.ms[1]<<8)|info->time.ms[0]);
			bus->printf("OV%s,"   ,OVinfo[QDS->part.OV]);
			bus->printf("BL%s,"   ,BLinfo[QDS->part.BL]);
			bus->printf("SB%s,"   ,SBinfo[QDS->part.SB]);
			bus->printf("NT%s,"   ,NTinfo[QDS->part.NT]);
			bus->printf("IV%s\r\n"   ,IVinfo[QDS->part.IV]);
		}
	}
	else {
		for (int i = 0 ; i < num ; ++i,++info){
			STD_t  * STD = &info->STD;
			*valset = STD->val[0]|(STD->val[1]<<8)|(STD->val[2]<<16)|(STD->val[3]<<24);
			bus->printf("addr:0x%x,val:%f,",addrlist[i],val);
			bus->printf("t:%d %d\r\n",
				info->time.min,(info->time.ms[1]<<8)|info->time.ms[0]);
		}
	}
	return 0;
}

int STD56T_pro(iec10x_t * bus , uint8_t num, uint32_t * addrlist ,void * data)
{
	STD56T_t * info = (STD56T_t*)data;
	float val;
	uint32_t *valset = (uint32_t*)&val;
	if (bus->dbglevel > IEC_DBG_HIGH){
		for (int i = 0 ; i < num ; ++i,++info){
			STD_t  * STD = &info->STD;
			QDS_t  * QDS = &info->QDS;
			*valset = STD->val[0]|(STD->val[1]<<8)|(STD->val[2]<<16)|(STD->val[3]<<24);
			bus->printf("addr:0x%x,val:%f,",addrlist[i],val);
			bus->printf("t:%d/%d/%d %d:%d\r\n",
				info->time.year,info->time.month,info->time.day.date ,
				info->time.hour,info->time.min);
			bus->printf("OV%s,"   ,OVinfo[QDS->part.OV]);
			bus->printf("BL%s,"   ,BLinfo[QDS->part.BL]);
			bus->printf("SB%s,"   ,SBinfo[QDS->part.SB]);
			bus->printf("NT%s,"   ,NTinfo[QDS->part.NT]);
			bus->printf("IV%s\r\n"   ,IVinfo[QDS->part.IV]);
		}
	}
	else {
		for (int i = 0 ; i < num ; ++i,++info){
			STD_t  * STD = &info->STD;
			*valset = STD->val[0]|(STD->val[1]<<8)|(STD->val[2]<<16)|(STD->val[3]<<24);
			bus->printf("addr:0x%x,val:%f,",addrlist[i],val);
			bus->printf("t:%d/%d/%d %d:%d\r\n",
				info->time.year,info->time.month,info->time.day.date ,
				info->time.hour,info->time.min);
		}
	}
	return 0;
}

/**
  * @brief    解析一帧 ASDU 信息
  * @author   古么宁 
  * @param    bus      : 总线
  * @param    data     : 接收到的报文
  * @param    type     : 报文类型 @see iec_pkt_t
  * @return   don't care
*/
static void ASDU_parse(iec10x_t * bus,unsigned char * ASDU,int ASDUlen)
{
	static const char * SQinfo[] = {
		"SQ=0:地址不连续" , "SQ=1:地址连续" 
	};
	IEC_INDEX(bus->causelen,bus->cmnaddrlen);
	int  SQ      = (ASDU[IEC_QUALIFIER] & 0x80) > 0 ;
	int  datanum =  ASDU[IEC_QUALIFIER] & (~0x80);
	uint16_t cmnaddr = ASDU[IEC_COMMON_ADDR];
	uint32_t * addrlistbuf;
	uint8_t  * usrinfo ;
	int argsize = iec_tysize[ASDU[0]];

	if (bus->cmnaddrlen > 1) {
		cmnaddr |= ASDU[IEC_COMMON_ADDR+1] << 8; 
	}
	bus->printf("common addr:0x%x\r\nnums:%d\r\n%s\r\n",cmnaddr,datanum,SQinfo[SQ]);

	if (bus->dbglevel < IEC_DBG_HIGH) {
		/* 打印等级小于 IEC_DBG_HIGH 返回 */
		return ;
	}

	if (ASDU[0] > 63 || !data_parser[ASDU[0]] || !argsize ) {
		/* 无可解析函数返回 */
		return ;
	}

	usrinfo = iec_malloc(sizeof(uint32_t)*datanum + 256);
	if (!usrinfo) {
		return ;
	}
	else {
		addrlistbuf = (uint32_t *)&usrinfo[256];
	}

	uint8_t  * usrdata ,* info = &ASDU[IEC_INFO];
	uint32_t * addrlist = addrlistbuf ;
	if (SQ) {
		uint32_t dataaddr = 0;  //信息结构体起始地址，即第一个信息结构体地址

		//合并起始的信息对象地址
		if (bus->infoaddrlen == 3) {
			dataaddr = info[0] | (info[1]<<8) | (info[2]<<16);
			info += 3;
		}
		else {
			dataaddr = info[0] | (info[1]<<8);
			info += 2;
		}
		
		//越过第一个信息对象地址，后面为连续的结构体数据.为每个结构体补全地址标识
		usrdata = info ; 
		for (int i = 0; i < datanum ; ++i) {
			*addrlist++ = dataaddr++;
		}
	}
	else {
		uint8_t * copy = usrinfo;
		usrdata = usrinfo ;
	
		for (int i = 0; i < datanum ; ++i,++addrlist) {
			// 提取当前结构体的信息对象地址
			if (bus->infoaddrlen == 3) {
				*addrlist = info[0] | (info[1]<<8) | (info[2]<<16);
				info += 3;
			}
			else {
				*addrlist = info[0] | (info[1]<<8);
				info += 2;
			}
			
			//不带对象地址的信息体长度
			for (int k = 0 ; k < argsize ; ++k){ 
				*copy++ = *info++;
			}
		}
	}

	data_parser[ASDU[0]](bus,datanum,addrlistbuf,usrdata);
	iec_free(usrinfo);
}


/**
  * @brief    解析一帧 101 不定长报文
  * @author   古么宁 
  * @param    bus      : 总线
  * @param    data     : 接收到的报文
  * @param    type     : 报文类型 @see iec_pkt_t
  * @return   don't care
*/
static void iec101_longpkt_parse(iec10x_t *bus,uint8_t * data ,iec_pkt_t type)
{
	struct longpkt * recvpkt  = (struct longpkt*)data;
	int32_t datalen = recvpkt->len + 4 + 2 ; //总包长。加上帧头(4)帧尾(2)
	uint32_t addr = recvpkt->linkaddr[0]; 
	uint8_t * ASDU    ;
	int       ASDUlen ;

	if (recvpkt->head != recvpkt->head2 || recvpkt->len2 != recvpkt->len){
		bus->printf("frame head error\r\n");
		return ;
	}
	else {
		bus->printf("pktlen = %d\r\n", recvpkt->len);
	}

	if (data[datalen - 1] != 0x16) {
		bus->printf("cannot found frame tail\r\n");
		return ;
	}

	if (bus->iec101.lnaddrlen > 1) {
		addr |= (recvpkt->linkaddr[1] << 8) ;
	}

	bus->printf("linkaddr:0x%x\r\n",addr);

	if (bus->iec101.lnaddr != addr) {
		bus->printf("address does not match.\r\n");
		return ;
	}

	ASDU    = &recvpkt->linkaddr[bus->iec101.lnaddrlen] ;
	ASDUlen = recvpkt->len - 1 - bus->iec101.lnaddrlen  ;

	int slv2mst = (bus->mode & IEC_MASTER) ^ type;

	/* 到此为校验正确的包，处理包数据 */
	if (!slv2mst) {
		if (bus->mode & IEC_BALANCE)
			bals_link_check(bus,recvpkt->linkctrl);
		else
			unbals_link_check(bus,recvpkt->linkctrl);
	}
	else { 
		if (bus->mode & IEC_BALANCE)
			balm_link_check(bus,recvpkt->linkctrl); 
		else 
			unbalm_link_check(bus,recvpkt->linkctrl);
	}

	if (ASDU[0] < 128) {
		bus->printf("COT:%s\r\nASDU:%s\r\n",
			COTinfo[ASDU[IEC_COT]],ASDUTYPinfo[ASDU[0]]);

		ASDU_parse(bus,ASDU,ASDUlen);
	}
}

/**
  * @brief    非平衡模式下做从机，解析判断链路层
  * @param    bus           : 需要解析的总线结构体 
  * @param    ctrlfrommaster: 来自主机的控制域
  * @return   don't care
*/
static void unbals_link_check(iec10x_t * bus , uint8_t ctrlfrommaster)
{
	linkctrl_t linkctrl = {.val = ctrlfrommaster};//提取控制码并分析
	bus->printf("fncode:%s\r\n",mstfncode[linkctrl.master.FUNCTION]);
}


/**
  * @brief    主机模式。如果已知固定帧长包包头，尝试解析
  *           在非平衡模式下，从机不会主动发数据，因此主机接收到数据一定是主机
  *           先发送了指令。所以此时的总线状态为忙碌。
  * @param    bus    : 需要解析的总线结构体 
  * @param    datapkt: 固定长度数据包
  * @param    pktlen : 固定长度数据包长度
  * @return   don't care
*/
static void unbalm_link_check(iec10x_t * bus , uint8_t ctrlfromslave)
{
	linkctrl_t linkctrl = {.val = ctrlfromslave};
	if (linkctrl.slave.ACD) {
		bus->printf("ACD=1:请求1级数据\r\n");
	}
	else {
		bus->printf("ACD=0.无1级数据\r\n");
	}
	
	bus->printf("fncode:%s\r\n",slvfncode[linkctrl.slave.FUNCTION]);
}

/**
  * @brief    平衡模式下做主机，解析判断链路层
  * @param    bus          : 需要解析的总线结构体 
  * @param    ctrlfromslave: 来自从机的控制域
  * @return   don't care
*/
static void balm_link_check(iec10x_t * bus , uint8_t ctrlfromslave)
{
	linkctrl_t linkctrl = {.val = ctrlfromslave};
	if (linkctrl.master.PRM) { 
		/* 数据包是从机主导发送的，此处 作出响应 */
		bus->printf("PRM=1,slave leading.\r\nfncode:%s\r\n"
			,mstfncode[linkctrl.master.FUNCTION]);
	}
	else {
		/* 接收到来自从机的响应 */
		bus->printf("PRM=0,slave confirm.\r\nfncode:%s\r\n"
			,slvfncode[linkctrl.slave.FUNCTION]);
	}
}

/**
  * @brief    平衡模式下做从机，解析链路层
  * @param    bus           : 需要解析的总线结构体 
  * @param    ctrlfrommaster: 来自主机的控制域
  * @return   don't care
*/
static void bals_link_check(iec10x_t * bus , uint8_t ctrlfrommaster)
{
	linkctrl_t linkctrl = {.val = ctrlfrommaster};
	
	if (linkctrl.master.PRM) {
		/* 数据包是主机主导发送的 */
		bus->printf("fncode:%s\r\n",mstfncode[linkctrl.master.FUNCTION]);
	}
	else {
		/* 接收到来自主机的响应 */
		bus->printf("fncode:%s\r\n",slvfncode[linkctrl.slave.FUNCTION]);
	}
}




/**
  * @brief    解析一帧 101 定长短报文
  * @author   古么宁 
  * @param    bus      : 总线
  * @param    data     : 接收到的报文
  * @param    type     : 报文类型 @see iec_pkt_t
  * @return   don't care
*/
static void iec101_shortpkt_parse(iec10x_t *bus,uint8_t * data ,iec_pkt_t type)
{
	int  datalen = 4 + bus->iec101.lnaddrlen;

	if (data[datalen-1] != 0x16 ) { //帧尾错误
		bus->printf("cannot found frame tail\r\n");
		return ;
	}

	int slv2mst = (bus->mode & IEC_MASTER) ^ type;

	if (slv2mst) {
		if (bus->mode & IEC_BALANCE) {
			balm_link_check(bus,data[1]);
		}
		else {
			unbalm_link_check(bus,data[1]);
		}
	}
	else {
		/* 主站 -> 从站的数据包 */
		if (bus->mode & IEC_BALANCE) {
			bals_link_check(bus,data[1]);
		}
		else {
			unbals_link_check(bus,data[1]);
		}
	}
}

static void packet_data(iec10x_t * bus,unsigned char * data , int pktlen ,iec_pkt_t pkttype)
{
	static const char const * titleinfo[] = {
		"S <<- M" , "M <<- S"  , "S ->> M", "M ->> S"
	};

	int title = (bus->mode & IEC_MASTER) | (pkttype << 1);

	bus->printf("\r\n%s (%d bytes):\r\n",titleinfo[title],pktlen);

	for (int i = 0 ; i < pktlen ; ) {
		bus->printf("%02x ", data[i]);
		if (((++i) % 20 ) == 0) { // 一行 20 个数据
			bus->printf("\r\n");
		}
	}
	if (pktlen % 20) {
		bus->printf("\r\n");
	}
}


/**
  * @brief    解析一帧 101 报文
  * @author   古么宁 
  * @param    bus      : 总线
  * @param    data     : 接收到的报文
  * @param    pktlen   : 接收到的报文长度
  * @param    pkttype  : 报文类型 @see iec_pkt_t
  * @return   don't care
*/
void iec101_packet_parser(iec10x_t * bus,unsigned char * data , int pktlen ,iec_pkt_t pkttype)
{
	packet_data(bus,data,pktlen,pkttype);
	if (data[0] == 0x10)
		iec101_shortpkt_parse(bus,data,pkttype);
	else
		iec101_longpkt_parse(bus,data,pkttype); 
}



static char * iec104_uframe(uint8_t ctrlval)
{
	char * msg ;
	if (ctrlval == 0x0B) {
		msg = "slave connected." ;
	}
	else
	if (ctrlval == 0x23) {
		msg = "slave disconnected." ;
	}
	else 
	if (ctrlval == 0x43) {
		msg = "heartbeat." ;
	}
	else
	if (ctrlval == 0x83){
		msg = "heartbeat reply." ;
	}
	else 
	if (ctrlval == 0x07) {
		msg = "connect request.";
	}
	else
	if (ctrlval == 0x13) {
		msg = "disconnect request.";
	}
	else {
		msg = "unknown packet.";
	}
	return msg ;
}


static void iec104_iframe(iec10x_t * bus ,const uint8_t * data ,uint16_t len)
{
	struct iec104pkt{
		uint8_t head    ;
		uint8_t len     ;
		uint8_t ctrls[4];
		uint8_t ASDU[1] ;
	}
	*pkt  = (struct iec104pkt*)data;
	uint16_t  recvcheck  , sendcheck ;
	uint8_t * ASDU = pkt->ASDU ;
	
	recvcheck = (pkt->ctrls[0] >> 1)|(pkt->ctrls[1] << 7);
	sendcheck = (pkt->ctrls[2] >> 1)|(pkt->ctrls[3] << 7);
	bus->printf("<I-frame>%d:%d\r\n",recvcheck,sendcheck);

	
	if (ASDU[0] < 128) {
		bus->printf("COT:%s\r\nASDU:%s\r\n",
			COTinfo[ASDU[IEC_COT]],ASDUTYPinfo[ASDU[0]]);
			
		ASDU_parse(bus,ASDU,pkt->len-4);
	}
}

/**
  * @brief    解析一帧 104 报文
  * @author   古么宁 
  * @param    bus      : 总线
  * @param    data     : 接收到的报文
  * @param    pktlen   : 接收到的报文长度
  * @param    pkttype  : 报文类型 @see iec_pkt_t
  * @return   don't care
*/
void iec104_packet_parser(iec10x_t * bus,unsigned char * data , int pktlen ,iec_pkt_t pkttype)
{
	packet_data(bus,data,pktlen,pkttype);
	
	if ((data[2] & 0x03) == 0x03) { // u 帧
		bus->printf("[U-frame]:%s\r\n",iec104_uframe(data[2]));
	}
	else
	if ((data[2] & 0x01) == 0x01) { // s 帧
		uint16_t txcheck = ((data[4]>>1)|(data[5]<<7));
		bus->printf("(S-frame):%d\r\n",txcheck);
	}
	else {
		iec104_iframe(bus,data,pktlen);
	}
}


void iec10x_parser_init(void)
{
	data_parser[M_SP_NA_1] = SIQ0T_parse  ;
	data_parser[C_SC_NA_1] = SIQ0T_parse  ;
	data_parser[M_SP_TA_1] = SIQ24T_parse ;
	data_parser[C_SC_TA_1] = SIQ56T_parse ;

	data_parser[M_DP_NA_1] = DIQ0T_parse  ;
	data_parser[C_DC_NA_1] = DIQ0T_parse  ;
	data_parser[M_DP_TA_1] = DIQ24T_parse ;
	data_parser[C_DC_TA_1] = DIQ56T_parse ;

	data_parser[M_ME_NC_1] = STD0T_pro    ;
	data_parser[M_ME_TC_1] = STD24T_pro   ;
	data_parser[M_ME_TF_1] = STD56T_pro   ;

	//data_parser[M_SP_NA_1] = SIQ0T_parse  ;
}

#endif /** #if (ENABLE_PKT_PARSER) */
